"use strict";

let fout = require('../../common/function.js').formatOutput;
let request = require('request');
let debug = require('debug')('elastic');

function BaseEsDao() {
    return this instanceof BaseEsDao ? this : new BaseEsDao();
}

module.exports = BaseEsDao;

let theProto = BaseEsDao.prototype;

theProto.init = function (metaInfo, esClient) {
    this.metaInfo = metaInfo;
    this.index = esClient.index;
    this.type = metaInfo.type;
    this.esClient = esClient;
    this.host = esClient.host;
    this.client = esClient.client;
    this.typeReady = false;
    esClient.createMappingIfNecessary(this.type, metaInfo.mapping);
};

theProto.checkReady = function () {
    if (!this.typeReady) {
        this.typeReady = this.esClient.readyType.indexOf(this.type) >= 0;
    }
    if (!this.typeReady) {
        throw new Error('elastic search not ready');
    }
};

/**
 * 删除数据,重建mapping
 */
theProto.deleteMapping = function*() {
    let self = this;
    this.typeReady = false;
    this.esClient.dropTypeReady(this.type);
    // delete the mapping
    let result = yield this.client.indices.deleteMapping({
        index: self.index,
        type: self.type
    });
    return result;
};

/**
 * create mapping
 * @returns {*}
 */
theProto.createMapping = function*() {
    let self = this;
    let result = yield this.client.indices.putMapping({
        index: self.index,
        type: self.type,
        ignoreConflicts: true,
        body: this.metaInfo.mapping
    });
    return result;
};

/**
 * quick search
 */
theProto.qSearch = function*(q) {
    let self = this;
    let res = yield this.client.search({
        index: self.index,
        type: self.type,
        q: q
    });
    return fout(0, null, res);
};

/**
 * delete all doc then rebuild the mapping
 * @returns {*}
 */
theProto.reBuild = function*() {
    yield this.deleteMapping();
    let res = yield this.createMapping();
    return res;
};

/**
 * create single doc index
 * @param json
 * @param idFieldName
 */
theProto.createSingle = function*(json, idFieldName) {
    this.checkReady();
    let self = this;
    debug('create, input', json);

    let item = {
        index: self.index,
        type: self.type,
        body: json
    };
    if (!idFieldName)
        idFieldName = 'articleId';
    if (json[idFieldName]) {
        item.id = json[idFieldName];
    }
    let res = yield this.client.create(item);
    return fout(0, null, res);
};

/**
 * bulk接口实现批量创建
 * @param list
 * @param idFieldName
 */
theProto.createMany = function*(list, idFieldName) {
    let body = [];
    let self = this;
    // 组装bulk对象
    for (let i = 0; i < list.length; i++) {
        let item = list[i];
        let index = {
            _index: self.index,
            _type: self.type
        };
        if (item[idFieldName]) {
            index._id = item[idFieldName];
        }

        let action = {index: index};
        body.push(action, item);
    }

    let result = yield this.client.bulk({body: body});
    return fout(0, null, result);
};

/**
 * 词频查询
 * @param field
 * @param topNum
 */
theProto.termFreq = function*(field, topNum) {
    let self = this;
    this.checkReady();

    let ret = yield this.getTremFreqResult(field);

    // sort by totalfreq desc
    ret.sort(function (a, b) {
        return b.totalfreq - a.totalfreq;
    });

    // filter
    let retFilter = [];
    ret.forEach(function (item) {
        if (self.filter(item.term)) retFilter.push(item);
    });

    retFilter.splice(topNum);
    //let needKey = ["totalfreq", "term"];
    let ret2 = {};
    retFilter.forEach(function (item) {
        ret2[item.term] = item.totalfreq;
    });

    return fout(0, null, ret2);
};

/**
 * 自定义打分 * 拼凑一个 json,发请求
 * @param json {q:"xx",add: 1, sub: 2, mul: 3}
 */
let urlCScore = 'http://host/index/type/_search';
theProto.cScore = function*(json) {
    let body = {
        "query": {
            "filtered": {
                "filter": {
                    "bool": {
                        "must": {
                            "term": {"articleContent": json.q}
                        }
                    }
                },

                "query": {
                    "function_score": {
                        "boost_mode": "replace",
                        "functions": [
                            {
                                "script_score": {
                                    "params": {"f_add": json.add, "f_sub": json.sub, "f_mul": json.mul},
                                    "script": "doc['uid'].value*f_mul + f_add - f_sub"
                                }
                            }
                        ]
                    }
                }
            }
        }
    };
    let url = urlCScore.replace('host', this.host);
    url = url.replace('index', this.index);
    url = url.replace('type', this.type);
    let result = yield this.requestPost(url, body);

    return result;
};

/**
 * 发送请求
 */
theProto.requestSend = function*(json) {
    return new Promise(function (fullfil, reject) {
        request(json, function (err, res, body) {
            if (err) throw err;
            fullfil(body);
        });
    }).then(function (body) {
            return body;
        });
};

/**
 * 发送 get请求
 * @param url
 * @returns {*}
 */
theProto.requestGet = function*(url) {
    let result = yield this.requestSend({url: url});
    return result;
};

/**
 * 发送 post 请求
 * @param url
 * @returns {*}
 */
theProto.requestPost = function*(url, body) {
    var json = {
        method: 'POST',
        url: url,
        json: true,
        headers: {"content-type": "application/json"},
        body: body
    };
    let result = yield this.requestSend(json);
    return result;
};

/**
 * 因为termFrequency 不是标准api,所以只能自己组装url,发送请求等待结果
 * /o2o/_termlist?field=title
 * @param field
 * @returns {string}
 */
let urlPattern = 'http://host/index/_termlist';
theProto.getTermFreqUrl = function (field) {
    let url = urlPattern.replace('host', this.host);
    url = url.replace('index', this.index);
    url = !!field ? url + '?field=' + field : url;
    return url;
};

/**
 * 获取 term frequency 分析结果,返回promise对象
 * @param field
 * @returns {Promise.<T>}
 */
theProto.getTremFreqResult = function *(field) {
    let url = this.getTermFreqUrl(field);
    let result = yield this.requestGet(url);
    result = JSON.parse(result);
    return result.terms;
};

/**
 * 词语过滤,过滤一些"无意义"的词汇
 * @param word
 * @returns {boolean}
 */
theProto.filter = function (word) {
    if (word.length < 2) {
        return false;
    }

    if (!isNaN(word)) { // number
        return false;
    }

    return true;
};
